//===--- Stmt.h - Swift Language Statement ASTs -----------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the Stmt class and subclasses.
//
//===----------------------------------------------------------------------===//

#ifndef POLARPHP_AST_TMT_H
#define POLARPHP_AST_TMT_H

#include "polarphp/ast/AstNode.h"
#include "polarphp/ast/Availability.h"
#include "polarphp/ast/AvailabilitySpec.h"
#include "polarphp/ast/ConcreteDeclRef.h"
#include "polarphp/ast/IfConfigClause.h"
#include "polarphp/ast/TypeAlignments.h"
#include "polarphp/basic/Debug.h"
#include "polarphp/basic/NullablePtr.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/TrailingObjects.h"

namespace polar {

class AnyPattern;
class AstContext;
class AstWalker;
class Decl;
class Expr;
class FuncDecl;
class Pattern;
class PatternBindingDecl;
class VarDecl;
class CaseStmt;

using polar::count_bits_used;
using polar::bitmax;
using polar::NullablePtr;
using polar::OptionalTransformRange;

enum class StmtKind
{
#define STMT(ID, PARENT) ID,
#define LAST_STMT(ID) Last_Stmt = ID,
#define STMT_RANGE(Id, FirstId, LastId) \
   First_##Id##Stmt = FirstId, Last_##Id##Stmt = LastId,
#include "polarphp/ast/StmtNodesDef.h"
};
enum : unsigned { NumStmtKindBits =
                  count_bits_used(static_cast<unsigned>(StmtKind::Last_Stmt)) };

/// Stmt - Base class for all statements in swift.
class alignas(8) Stmt {
   Stmt(const Stmt&) = delete;
   Stmt& operator=(const Stmt&) = delete;

   protected:
   union { uint64_t OpaqueBits;

           POLAR_INLINE_BITFIELD_BASE(Stmt, bitmax(NumStmtKindBits,8) + 1,
                                      /// Kind - The subclass of Stmt that this is.
                                      Kind : bitmax(NumStmtKindBits,8),

                                      /// Implicit - Whether this statement is implicit.
                                      Implicit : 1
                                      );

                POLAR_INLINE_BITFIELD_FULL(BraceStmt, Stmt, 32,
                                           : NumPadBits,
                                           NumElements : 32
                                           );

                     POLAR_INLINE_BITFIELD_FULL(CaseStmt, Stmt, 32,
                                                : NumPadBits,
                                                NumPatterns : 32
                                                );

                          POLAR_INLINE_BITFIELD_EMPTY(LabeledStmt, Stmt);

                               POLAR_INLINE_BITFIELD_FULL(DoCatchStmt, LabeledStmt, 32,
                                                          : NumPadBits,
                                                          NumCatches : 32
                                                          );

                                    POLAR_INLINE_BITFIELD_FULL(SwitchStmt, LabeledStmt, 32,
                                                               : NumPadBits,
                                                               CaseCount : 32
                                                               );

                                         POLAR_INLINE_BITFIELD_FULL(YieldStmt, Stmt, 32,
                                                                    : NumPadBits,
                                                                    NumYields : 32
                                                                    );

         } Bits;

   /// Return the given value for the 'implicit' flag if present, or if None,
   /// return true if the location is invalid.
   static bool getDefaultImplicitFlag(Optional<bool> implicit, SourceLoc keyLoc){
      return implicit.hasValue() ? *implicit : keyLoc.isInvalid();
   }

   public:
   Stmt(StmtKind kind, bool implicit) {
      Bits.OpaqueBits = 0;
      Bits.Stmt.Kind = static_cast<unsigned>(kind);
      Bits.Stmt.Implicit = implicit;
   }

   StmtKind getKind() const { return StmtKind(Bits.Stmt.Kind); }

   /// Retrieve the name of the given statement kind.
   ///
   /// This name should only be used for debugging dumps and other
   /// developer aids, and should never be part of a diagnostic or exposed
   /// to the user of the compiler in any way.
   static StringRef getKindName(StmtKind kind);

   /// Return the location of the start of the statement.
   SourceLoc getStartLoc() const;

   /// Return the location of the end of the statement.
   SourceLoc getEndLoc() const;

   SourceRange getSourceRange() const;
   SourceLoc TrailingSemiLoc;

   /// isImplicit - Determines whether this statement was implicitly-generated,
   /// rather than explicitly written in the AST.
   bool isImplicit() const { return Bits.Stmt.Implicit; }

   /// walk - This recursively walks the AST rooted at this statement.
   Stmt *walk(AstWalker &walker);
   Stmt *walk(AstWalker &&walker) { return walk(walker); }

   POLAR_DEBUG_DUMP;
   void dump(raw_ostream &OS, const AstContext *Ctx = nullptr, unsigned Indent = 0) const;

   // Only allow allocation of Exprs using the allocator in AstContext
   // or by doing a placement new.
   void *operator new(size_t Bytes, AstContext &C,
                      unsigned Alignment = alignof(Stmt));

   // Make vanilla new/delete illegal for Stmts.
   void *operator new(size_t Bytes) throw() = delete;
   void operator delete(void *Data) throw() = delete;
   void *operator new(size_t Bytes, void *Mem) throw() = delete;
};

/// BraceStmt - A brace enclosed sequence of expressions, stmts, or decls, like
/// { var x = 10; print(10) }.
class BraceStmt final : public Stmt,
      private llvm::TrailingObjects<BraceStmt, AstNode> {
   friend TrailingObjects;

   SourceLoc LBLoc;
   SourceLoc RBLoc;

   BraceStmt(SourceLoc lbloc, ArrayRef<AstNode> elements,SourceLoc rbloc,
             Optional<bool> implicit);

public:
   static BraceStmt *create(AstContext &ctx, SourceLoc lbloc,
                            ArrayRef<AstNode> elements,
                            SourceLoc rbloc,
                            Optional<bool> implicit = None);

   SourceLoc getLBraceLoc() const { return LBLoc; }
   SourceLoc getRBraceLoc() const { return RBLoc; }

   SourceRange getSourceRange() const { return SourceRange(LBLoc, RBLoc); }

   bool empty() const { return getNumElements() == 0; }
   unsigned getNumElements() const { return Bits.BraceStmt.NumElements; }

   AstNode getFirstElement() const { return getElements().front(); }
   AstNode getLastElement() const { return getElements().back(); }

   void setFirstElement(AstNode node) { getElements().front() = node; }

   /// The elements contained within the BraceStmt.
   MutableArrayRef<AstNode> getElements() {
      return {getTrailingObjects<AstNode>(), Bits.BraceStmt.NumElements};
   }

   /// The elements contained within the BraceStmt (const version).
   ArrayRef<AstNode> getElements() const {
      return {getTrailingObjects<AstNode>(), Bits.BraceStmt.NumElements};
   }

   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Brace; }
};

/// ReturnStmt - A return statement.  The result is optional; "return" without
/// an expression is semantically equivalent to "return ()".
///    return 42
class ReturnStmt : public Stmt {
   SourceLoc ReturnLoc;
   Expr *Result;

public:
   ReturnStmt(SourceLoc ReturnLoc, Expr *Result,
              Optional<bool> implicit = None)
      : Stmt(StmtKind::Return, getDefaultImplicitFlag(implicit, ReturnLoc)),
        ReturnLoc(ReturnLoc), Result(Result) {}

   SourceLoc getReturnLoc() const { return ReturnLoc; }

   SourceLoc getStartLoc() const;
   SourceLoc getEndLoc() const;

   bool hasResult() const { return Result != 0; }
   Expr *getResult() const {
      assert(Result && "ReturnStmt doesn't have a result");
      return Result;
   }
   void setResult(Expr *e) { Result = e; }

   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Return;}
};

/// YieldStmt - A yield statement.  The yield-values sequence is not optional,
/// but the parentheses are.
///    yield 42
class YieldStmt final
      : public Stmt, private llvm::TrailingObjects<YieldStmt, Expr*> {
   friend TrailingObjects;

   SourceLoc YieldLoc;
   SourceLoc LPLoc;
   SourceLoc RPLoc;

   YieldStmt(SourceLoc yieldLoc, SourceLoc lpLoc, ArrayRef<Expr *> yields,
             SourceLoc rpLoc, Optional<bool> implicit = None)
      : Stmt(StmtKind::Yield, getDefaultImplicitFlag(implicit, yieldLoc)),
        YieldLoc(yieldLoc), LPLoc(lpLoc), RPLoc(rpLoc) {
      Bits.YieldStmt.NumYields = yields.size();
      memcpy(getMutableYields().data(), yields.data(),
             yields.size() * sizeof(Expr*));
   }

public:
   static YieldStmt *create(const AstContext &ctx, SourceLoc yieldLoc,
                            SourceLoc lp, ArrayRef<Expr*> yields, SourceLoc rp,
                            Optional<bool> implicit = None);

   SourceLoc getYieldLoc() const { return YieldLoc; }
   SourceLoc getLParenLoc() const { return LPLoc; }
   SourceLoc getRParenLoc() const { return RPLoc; }

   SourceLoc getStartLoc() const { return YieldLoc; }
   SourceLoc getEndLoc() const;

   ArrayRef<Expr*> getYields() const {
      return {getTrailingObjects<Expr*>(), Bits.YieldStmt.NumYields};
   }
   MutableArrayRef<Expr*> getMutableYields() {
      return {getTrailingObjects<Expr*>(), Bits.YieldStmt.NumYields};
   }

   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Yield; }
};

/// DeferStmt - A 'defer' statement.  This runs the substatement it contains
/// when the enclosing scope is exited.
///
///    defer { cleanUp() }
///
/// The AST representation for a defer statement is a bit weird.  We model this
/// as if they wrote:
///
///    func tmpClosure() { body }
///    tmpClosure()   // This is emitted on each path that needs to run this.
///
/// As such, the body of the 'defer' is actually type checked within the
/// closure's DeclContext.  We do this because of unfortunateness in SILGen,
/// some expressions (e.g. OpenExistentialExpr) cannot be multiply emitted in a
/// composable way.  When this gets fixed, patches r27767 and r27768 can be
/// reverted to go back to the simpler and more obvious representation.
///
class DeferStmt : public Stmt
{
   SourceLoc DeferLoc;

   /// This is the bound temp function.
   FuncDecl *tempDecl;

   /// This is the invocation of the closure, which is to be emitted on any error
   /// paths.
   Expr *callExpr;

public:
   DeferStmt(SourceLoc DeferLoc,
             FuncDecl *tempDecl, Expr *callExpr)
      : Stmt(StmtKind::Defer, /*implicit*/false),
        DeferLoc(DeferLoc), tempDecl(tempDecl),
        callExpr(callExpr) {}

   SourceLoc getDeferLoc() const { return DeferLoc; }

   SourceLoc getStartLoc() const { return DeferLoc; }
   SourceLoc getEndLoc() const;

   FuncDecl *getTempDecl() const { return tempDecl; }
   Expr *getCallExpr() const { return callExpr; }
   void setCallExpr(Expr *E) { callExpr = E; }

   /// Dig the original user's body of the defer out for AST fidelity.
   BraceStmt *getBodyAsWritten() const;

   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Defer; }
};


/// An expression that guards execution based on whether the run-time
/// configuration supports a given API, e.g.,
/// #available(OSX >= 10.9, iOS >= 7.0).
class alignas(8) PoundAvailableInfo final :
   private llvm::TrailingObjects<PoundAvailableInfo, AvailabilitySpec *> {
              friend TrailingObjects;

SourceLoc PoundLoc;
SourceLoc RParenLoc;

// The number of queries tail allocated after this object.
unsigned NumQueries;

/// The version range when this query will return true. This value is
/// filled in by Sema.
VersionRange AvailableRange;

PoundAvailableInfo(SourceLoc PoundLoc, ArrayRef<AvailabilitySpec *> queries,
                   SourceLoc RParenLoc)
   : PoundLoc(PoundLoc), RParenLoc(RParenLoc), NumQueries(queries.size()),
     AvailableRange(VersionRange::empty()) {
   std::uninitialized_copy(queries.begin(), queries.end(),
                           getTrailingObjects<AvailabilitySpec *>());
}

public:
static PoundAvailableInfo *create(AstContext &ctx, SourceLoc PoundLoc,
                                  ArrayRef<AvailabilitySpec *> queries,
                                  SourceLoc RParenLoc);

ArrayRef<AvailabilitySpec *> getQueries() const {
   return llvm::makeArrayRef(getTrailingObjects<AvailabilitySpec *>(),
                             NumQueries);
}

SourceLoc getStartLoc() const { return PoundLoc; }
SourceLoc getEndLoc() const;
SourceLoc getLoc() const { return PoundLoc; }
SourceRange getSourceRange() const { return SourceRange(getStartLoc(),
                                                        getEndLoc()); }

const VersionRange &getAvailableRange() const { return AvailableRange; }
void setAvailableRange(const VersionRange &Range) { AvailableRange = Range; }
};


/// This represents an entry in an "if" or "while" condition.  Pattern bindings
/// can bind any number of names in the pattern binding decl, and may have an
/// associated where clause.  When "if let" is involved, an arbitrary number of
/// pattern bindings and conditional expressions are permitted, e.g.:
///
///   if let x = ..., y = ... where x > y,
///      let z = ...
/// which would be represented as four StmtConditionElement entries, one for
/// the "x" binding, one for the "y" binding, one for the where clause, one for
/// "z"'s binding.  A simple "if" statement is represented as a single binding.
///
class StmtConditionElement
{
   /// If this is a pattern binding, it may be the first one in a declaration, in
   /// which case this is the location of the var/let/case keyword.  If this is
   /// the second pattern (e.g. for 'y' in "var x = ..., y = ...") then this
   /// location is invalid.
   SourceLoc IntroducerLoc;

   /// In a pattern binding, this is pattern being matched.  In the case of an
   /// "implicit optional" pattern, the OptionalSome pattern is explicitly added
   /// to this as an 'implicit' pattern.
   Pattern *ThePattern = nullptr;

   /// This is either the boolean condition, the initializer for a pattern
   /// binding, or the #available information.
   llvm::PointerUnion<PoundAvailableInfo*, Expr *> CondInitOrAvailable;

public:
   StmtConditionElement() {}
   StmtConditionElement(SourceLoc IntroducerLoc, Pattern *ThePattern,
                        Expr *Init)
      : IntroducerLoc(IntroducerLoc), ThePattern(ThePattern),
        CondInitOrAvailable(Init) {}
   StmtConditionElement(Expr *cond) : CondInitOrAvailable(cond) {}

   StmtConditionElement(PoundAvailableInfo *Info) : CondInitOrAvailable(Info) {}

   SourceLoc getIntroducerLoc() const { return IntroducerLoc; }
   void setIntroducerLoc(SourceLoc loc) { IntroducerLoc = loc; }

   /// ConditionKind - This indicates the sort of condition this is.
   enum ConditionKind {
      CK_Boolean,
      CK_PatternBinding,
      CK_Availability
   };

   ConditionKind getKind() const {
      if (ThePattern) return CK_PatternBinding;
      return CondInitOrAvailable.is<Expr*>() ? CK_Boolean : CK_Availability;
   }

   /// Boolean Condition Accessors.
   Expr *getBooleanOrNull() const {
      return getKind() == CK_Boolean ? CondInitOrAvailable.get<Expr*>() : nullptr;
   }

   Expr *getBoolean() const {
      assert(getKind() == CK_Boolean && "Not a condition");
      return CondInitOrAvailable.get<Expr*>();
   }
   void setBoolean(Expr *E) {
      assert(getKind() == CK_Boolean && "Not a condition");
      CondInitOrAvailable = E;
   }

   /// Pattern Binding Accessors.
   Pattern *getPatternOrNull() const {
      return ThePattern;
   }

   Pattern *getPattern() const {
      assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
      return ThePattern;
   }

   void setPattern(Pattern *P) {
      assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
      ThePattern = P;
   }

   Expr *getInitializer() const {
      assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
      return CondInitOrAvailable.get<Expr*>();
   }
   void setInitializer(Expr *E) {
      assert(getKind() == CK_PatternBinding && "Not a pattern binding condition");
      CondInitOrAvailable = E;
   }

   // Availability Accessors
   PoundAvailableInfo *getAvailability() const {
      assert(getKind() == CK_Availability && "Not an #available condition");
      return CondInitOrAvailable.get<PoundAvailableInfo*>();
   }

   void setAvailability(PoundAvailableInfo *Info) {
      assert(getKind() == CK_Availability && "Not an #available condition");
      CondInitOrAvailable = Info;
   }

   SourceLoc getStartLoc() const;
   SourceLoc getEndLoc() const;
   SourceRange getSourceRange() const;

   /// Recursively walks the AST rooted at this statement condition element
   StmtConditionElement *walk(AstWalker &walker);
   StmtConditionElement *walk(AstWalker &&walker) { return walk(walker); }
};

struct LabeledStmtInfo
{
   Identifier Name;
   SourceLoc Loc;

   // Evaluates to true if set.
   operator bool() const { return !Name.empty(); }
};

/// LabeledStmt - Common base class between the labeled statements (loops and
/// switch).
class LabeledStmt : public Stmt
{
   LabeledStmtInfo LabelInfo;
protected:
   SourceLoc getLabelLocOrKeywordLoc(SourceLoc L) const {
      return LabelInfo ? LabelInfo.Loc : L;
   }
public:
   LabeledStmt(StmtKind Kind, bool Implicit, LabeledStmtInfo LabelInfo)
      : Stmt(Kind, Implicit), LabelInfo(LabelInfo) {}

   LabeledStmtInfo getLabelInfo() const { return LabelInfo; }
   void setLabelInfo(LabeledStmtInfo L) { LabelInfo = L; }

   /// Is this statement a valid target of "continue" if labeled?
   ///
   /// For the most part, non-looping constructs shouldn't be
   /// continue-able, but we threw in "do" as a sop.
   bool isPossibleContinueTarget() const;

   /// Is this statement a valid target of an unlabeled "break" or
   /// "continue"?
   ///
   /// The nice, consistent language rule is that unlabeled "break" and
   /// "continue" leave the innermost loop.  We have to include
   /// "switch" (for "break") for consistency with C: Swift doesn't
   /// require "break" to leave a switch case, but it's still way too
   /// similar to C's switch to allow different behavior for "break".
   bool requiresLabelOnJump() const;

   static bool classof(const Stmt *S) {
      return S->getKind() >= StmtKind::First_LabeledStmt &&
            S->getKind() <= StmtKind::Last_LabeledStmt;
   }
};


/// DoStmt - do statement, without any trailing clauses.
class DoStmt : public LabeledStmt
{
   SourceLoc DoLoc;
   Stmt *Body;

public:
   DoStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc,
          Stmt *body, Optional<bool> implicit = None)
      : LabeledStmt(StmtKind::Do, getDefaultImplicitFlag(implicit, doLoc),
                    labelInfo),
        DoLoc(doLoc), Body(body) {}

   SourceLoc getDoLoc() const { return DoLoc; }

   SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(DoLoc); }
   SourceLoc getEndLoc() const { return Body->getEndLoc(); }

   Stmt *getBody() const { return Body; }
   void setBody(Stmt *s) { Body = s; }

   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Do; }
};

/// An individual 'catch' clause.
///
/// This isn't really an independent statement any more than CaseStmt
/// is; it's just a structural part of a DoCatchStmt.
class CatchStmt : public Stmt
{
   SourceLoc CatchLoc;
   SourceLoc WhereLoc;
   Pattern *ErrorPattern;
   Expr *GuardExpr;
   Stmt *CatchBody;

public:
   CatchStmt(SourceLoc catchLoc, Pattern *errorPattern,
             SourceLoc whereLoc, Expr *guardExpr, Stmt *body,
             Optional<bool> implicit = None)
      : Stmt(StmtKind::Catch, getDefaultImplicitFlag(implicit, catchLoc)),
        CatchLoc(catchLoc), WhereLoc(whereLoc),
        ErrorPattern(nullptr), GuardExpr(guardExpr), CatchBody(body) {
      setErrorPattern(errorPattern);
   }

   SourceLoc getCatchLoc() const { return CatchLoc; }

   /// The location of the 'where' keyword if there's a guard expression.
   SourceLoc getWhereLoc() const { return WhereLoc; }

   SourceLoc getStartLoc() const { return CatchLoc; }
   SourceLoc getEndLoc() const { return CatchBody->getEndLoc(); }

   Stmt *getBody() const { return CatchBody; }
   void setBody(Stmt *body) { CatchBody = body; }

   Pattern *getErrorPattern() { return ErrorPattern; }
   const Pattern *getErrorPattern() const { return ErrorPattern; }
   void setErrorPattern(Pattern *pattern);

   /// Is this catch clause "syntactically exhaustive"?
   bool isSyntacticallyExhaustive() const;

   /// Return the guard expression if present, or null if the catch has
   /// no guard.
   Expr *getGuardExpr() const { return GuardExpr; }
   void setGuardExpr(Expr *guard) { GuardExpr = guard; }

   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Catch; }
};

/// DoCatchStmt - do statement with trailing 'catch' clauses.
class DoCatchStmt final : public LabeledStmt,
      private llvm::TrailingObjects<DoCatchStmt, CatchStmt *> {
   friend TrailingObjects;

   SourceLoc DoLoc;
   Stmt *Body;

   DoCatchStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc,
               Stmt *body, ArrayRef<CatchStmt*> catches,
               Optional<bool> implicit)
      : LabeledStmt(StmtKind::DoCatch, getDefaultImplicitFlag(implicit, doLoc),
                    labelInfo), DoLoc(doLoc), Body(body) {
      Bits.DoCatchStmt.NumCatches = catches.size();
      std::uninitialized_copy(catches.begin(), catches.end(),
                              getTrailingObjects<CatchStmt *>());
   }

public:
   static DoCatchStmt *create(AstContext &ctx, LabeledStmtInfo labelInfo,
                              SourceLoc doLoc, Stmt *body,
                              ArrayRef<CatchStmt*> catches,
                              Optional<bool> implicit = None);

   SourceLoc getDoLoc() const { return DoLoc; }

   SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(DoLoc); }
   SourceLoc getEndLoc() const { return getCatches().back()->getEndLoc(); }

   Stmt *getBody() const { return Body; }
   void setBody(Stmt *s) { Body = s; }

   ArrayRef<CatchStmt*> getCatches() const {
      return {getTrailingObjects<CatchStmt*>(), Bits.DoCatchStmt.NumCatches};
   }
   MutableArrayRef<CatchStmt*> getMutableCatches() {
      return {getTrailingObjects<CatchStmt*>(), Bits.DoCatchStmt.NumCatches};
   }

   /// Does this statement contain a syntactically exhaustive catch
   /// clause?
   ///
   /// Note that an exhaustive do/catch statement can still throw
   /// errors out of its catch block(s).
   bool isSyntacticallyExhaustive() const;

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::DoCatch;
   }
};


/// Either an "if let" case or a simple boolean expression can appear as the
/// condition of an 'if' or 'while' statement.
using StmtCondition = MutableArrayRef<StmtConditionElement>;

/// This is the common base class between statements that can have labels, and
/// also have complex "if let" style conditions: 'if' and 'while'.
class LabeledConditionalStmt : public LabeledStmt {
   StmtCondition Cond;
public:
   LabeledConditionalStmt(StmtKind Kind, bool Implicit,
                          LabeledStmtInfo LabelInfo, StmtCondition Cond)
      : LabeledStmt(Kind, Implicit, LabelInfo) {
      setCond(Cond);
   }

   StmtCondition getCond() const { return Cond; }
   void setCond(StmtCondition e);

   static bool classof(const Stmt *S) {
      return S->getKind() >= StmtKind::First_LabeledConditionalStmt &&
            S->getKind() <= StmtKind::Last_LabeledConditionalStmt;
   }
};


/// IfStmt - if/then/else statement.  If no 'else' is specified, then the
/// ElseLoc location is not specified and the Else statement is null. After
/// type-checking, the condition is of type Builtin.Int1.
class IfStmt : public LabeledConditionalStmt {
   SourceLoc IfLoc;
   SourceLoc ElseLoc;
   Stmt *Then;
   Stmt *Else;

public:
   IfStmt(LabeledStmtInfo LabelInfo, SourceLoc IfLoc, StmtCondition Cond,
          Stmt *Then, SourceLoc ElseLoc, Stmt *Else,
          Optional<bool> implicit = None)
      : LabeledConditionalStmt(StmtKind::If,
                               getDefaultImplicitFlag(implicit, IfLoc),
                               LabelInfo, Cond),
        IfLoc(IfLoc), ElseLoc(ElseLoc), Then(Then), Else(Else) {}

   IfStmt(SourceLoc IfLoc, Expr *Cond, Stmt *Then, SourceLoc ElseLoc,
          Stmt *Else, Optional<bool> implicit, AstContext &Ctx);

   SourceLoc getIfLoc() const { return IfLoc; }
   SourceLoc getElseLoc() const { return ElseLoc; }

   SourceLoc getStartLoc() const {
      return getLabelLocOrKeywordLoc(IfLoc);
   }
   SourceLoc getEndLoc() const {
      return (Else ? Else->getEndLoc() : Then->getEndLoc());
   }

   Stmt *getThenStmt() const { return Then; }
   void setThenStmt(Stmt *s) { Then = s; }

   Stmt *getElseStmt() const { return Else; }
   void setElseStmt(Stmt *s) { Else = s; }

   // Implement isa/cast/dyncast/etc.
   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::If; }
};

/// GuardStmt - 'guard' statement.  Evaluate a condition and if it fails, run
/// its body.  The body is always guaranteed to exit the current scope (or
/// abort), it never falls through.
///
class GuardStmt : public LabeledConditionalStmt {
   SourceLoc GuardLoc;
   Stmt *Body;

public:
   GuardStmt(SourceLoc GuardLoc, StmtCondition Cond,
             Stmt *Body, Optional<bool> implicit = None)
      : LabeledConditionalStmt(StmtKind::Guard,
                               getDefaultImplicitFlag(implicit, GuardLoc),
                               LabeledStmtInfo(), Cond),
        GuardLoc(GuardLoc), Body(Body) {}

   GuardStmt(SourceLoc GuardLoc, Expr *Cond, Stmt *Body,
             Optional<bool> implicit, AstContext &Ctx);

   SourceLoc getGuardLoc() const { return GuardLoc; }

   SourceLoc getStartLoc() const {
      return getLabelLocOrKeywordLoc(GuardLoc);
   }
   SourceLoc getEndLoc() const {
      return Body->getEndLoc();
   }

   Stmt *getBody() const { return Body; }
   void setBody(Stmt *s) { Body = s; }

   // Implement isa/cast/dyncast/etc.
   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Guard; }
};

/// WhileStmt - while statement. After type-checking, the condition is of
/// type Builtin.Int1.
class WhileStmt : public LabeledConditionalStmt {
   SourceLoc WhileLoc;
   StmtCondition Cond;
   Stmt *Body;

public:
   WhileStmt(LabeledStmtInfo LabelInfo, SourceLoc WhileLoc, StmtCondition Cond,
             Stmt *Body, Optional<bool> implicit = None)
      : LabeledConditionalStmt(StmtKind::While,
                               getDefaultImplicitFlag(implicit, WhileLoc),
                               LabelInfo, Cond),
        WhileLoc(WhileLoc), Body(Body) {}

   SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(WhileLoc); }
   SourceLoc getEndLoc() const { return Body->getEndLoc(); }

   Stmt *getBody() const { return Body; }
   void setBody(Stmt *s) { Body = s; }

   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::While; }
};

/// RepeatWhileStmt - repeat/while statement. After type-checking, the
/// condition is of type Builtin.Int1.
class RepeatWhileStmt : public LabeledStmt {
   SourceLoc RepeatLoc, WhileLoc;
   Stmt *Body;
   Expr *Cond;

public:
   RepeatWhileStmt(LabeledStmtInfo LabelInfo, SourceLoc RepeatLoc, Expr *Cond,
                   SourceLoc WhileLoc, Stmt *Body, Optional<bool> implicit = None)
      : LabeledStmt(StmtKind::RepeatWhile,
                    getDefaultImplicitFlag(implicit, RepeatLoc),
                    LabelInfo),
        RepeatLoc(RepeatLoc), WhileLoc(WhileLoc), Body(Body), Cond(Cond) {}

   SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(RepeatLoc); }
   SourceLoc getEndLoc() const;

   Stmt *getBody() const { return Body; }
   void setBody(Stmt *s) { Body = s; }

   Expr *getCond() const { return Cond; }
   void setCond(Expr *e) { Cond = e; }

   static bool classof(const Stmt *S) {return S->getKind() == StmtKind::RepeatWhile;}
};

/// ForEachStmt - foreach statement that iterates over the elements in a
/// container.
///
/// Example:
/// \code
/// for i in 0...10 {
///   print(String(i))
/// }
/// \endcode
class ForEachStmt : public LabeledStmt {
   SourceLoc ForLoc;
   Pattern *Pat;
   SourceLoc InLoc;
   Expr *Sequence;
   Expr *WhereExpr = nullptr;
   BraceStmt *Body;

   // Set by Sema:
   InterfaceConformanceRef sequenceConformance = InterfaceConformanceRef();
   ConcreteDeclRef makeIterator;
   ConcreteDeclRef iteratorNext;
   VarDecl *iteratorVar = nullptr;
   Expr *iteratorVarRef = nullptr;
   OpaqueValueExpr *elementExpr = nullptr;
   Expr *convertElementExpr = nullptr;

public:
   ForEachStmt(LabeledStmtInfo LabelInfo, SourceLoc ForLoc, Pattern *Pat,
               SourceLoc InLoc, Expr *Sequence, Expr *WhereExpr, BraceStmt *Body,
               Optional<bool> implicit = None)
      : LabeledStmt(StmtKind::ForEach, getDefaultImplicitFlag(implicit, ForLoc),
                    LabelInfo),
        ForLoc(ForLoc), Pat(nullptr), InLoc(InLoc), Sequence(Sequence),
        WhereExpr(WhereExpr), Body(Body) {
      setPattern(Pat);
   }

   void setIteratorVar(VarDecl *var) { iteratorVar = var; }
   VarDecl *getIteratorVar() const { return iteratorVar; }

   void setIteratorVarRef(Expr *var) { iteratorVarRef = var; }
   Expr *getIteratorVarRef() const { return iteratorVarRef; }

   void setElementExpr(OpaqueValueExpr *expr) { elementExpr = expr; }
   OpaqueValueExpr *getElementExpr() const { return elementExpr; }

   void setConvertElementExpr(Expr *expr) { convertElementExpr = expr; }
   Expr *getConvertElementExpr() const { return convertElementExpr; }

   void setMakeIterator(ConcreteDeclRef declRef) { makeIterator = declRef; }
   ConcreteDeclRef getMakeIterator() const { return makeIterator; }

   void setIteratorNext(ConcreteDeclRef declRef) { iteratorNext = declRef; }
   ConcreteDeclRef getIteratorNext() const { return iteratorNext; }

   void setSequenceConformance(InterfaceConformanceRef conformance) {
      sequenceConformance = conformance;
   }
   InterfaceConformanceRef getSequenceConformance() const {
      return sequenceConformance;
   }

   /// getForLoc - Retrieve the location of the 'for' keyword.
   SourceLoc getForLoc() const { return ForLoc; }

   /// getInLoc - Retrieve the location of the 'in' keyword.
   SourceLoc getInLoc() const { return InLoc; }

   /// getPattern - Retrieve the pattern describing the iteration variables.
   /// These variables will only be visible within the body of the loop.
   Pattern *getPattern() const { return Pat; }
   void setPattern(Pattern *p);

   Expr *getWhere() const { return WhereExpr; }
   void setWhere(Expr *W) { WhereExpr = W; }

   /// getSequence - Retrieve the Sequence whose elements will be visited
   /// by this foreach loop, as it was written in the source code and
   /// subsequently type-checked. To determine the semantic behavior of this
   /// expression to extract a range, use \c getRangeInit().
   Expr *getSequence() const { return Sequence; }
   void setSequence(Expr *S) { Sequence = S; }

   /// getBody - Retrieve the body of the loop.
   BraceStmt *getBody() const { return Body; }
   void setBody(BraceStmt *B) { Body = B; }

   SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(ForLoc); }
   SourceLoc getEndLoc() const { return Body->getEndLoc(); }

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::ForEach;
   }
};

/// A pattern and an optional guard expression used in a 'case' statement.
class CaseLabelItem {
   enum class Kind {
      /// A normal pattern
      Normal = 0,
      /// `default`
      Default,
   };

   Pattern *CasePattern;
   SourceLoc WhereLoc;
   llvm::PointerIntPair<Expr *, 1, Kind> GuardExprAndKind;

   CaseLabelItem(Kind kind, Pattern *casePattern, SourceLoc whereLoc,
                 Expr *guardExpr)
      : CasePattern(casePattern), WhereLoc(whereLoc),
        GuardExprAndKind(guardExpr, kind) {}

public:
   CaseLabelItem(const CaseLabelItem &) = default;

   CaseLabelItem(Pattern *casePattern, SourceLoc whereLoc, Expr *guardExpr)
      : CaseLabelItem(Kind::Normal, casePattern, whereLoc, guardExpr) {}
   explicit CaseLabelItem(Pattern *casePattern)
      : CaseLabelItem(casePattern, SourceLoc(), nullptr) {}

   static CaseLabelItem getDefault(AnyPattern *pattern,
                                   SourceLoc whereLoc,
                                   Expr *guardExpr) {
      assert(pattern);
      return CaseLabelItem(Kind::Default, reinterpret_cast<Pattern *>(pattern),
                           whereLoc, guardExpr);
   }
   static CaseLabelItem getDefault(AnyPattern *pattern) {
      return getDefault(pattern, SourceLoc(), nullptr);
   }

   SourceLoc getWhereLoc() const { return WhereLoc; }

   SourceLoc getStartLoc() const;
   SourceLoc getEndLoc() const;
   SourceRange getSourceRange() const;

   Pattern *getPattern() { return CasePattern; }
   const Pattern *getPattern() const { return CasePattern; }
   void setPattern(Pattern *CasePattern) { this->CasePattern = CasePattern; }

   /// Return the guard expression if present, or null if the case label has
   /// no guard.
   Expr *getGuardExpr() { return GuardExprAndKind.getPointer(); }
   const Expr *getGuardExpr() const {
      return GuardExprAndKind.getPointer();
   }
   void setGuardExpr(Expr *e) { GuardExprAndKind.setPointer(e); }

   /// Returns true if this is syntactically a 'default' label.
   bool isDefault() const {
      return GuardExprAndKind.getInt() == Kind::Default;
   }
};

/// FallthroughStmt - The keyword "fallthrough".
class FallthroughStmt : public Stmt {
   SourceLoc Loc;
   CaseStmt *FallthroughSource;
   CaseStmt *FallthroughDest;

public:
   FallthroughStmt(SourceLoc Loc, Optional<bool> implicit = None)
      : Stmt(StmtKind::Fallthrough, getDefaultImplicitFlag(implicit, Loc)),
        Loc(Loc), FallthroughSource(nullptr), FallthroughDest(nullptr) {}

   SourceLoc getLoc() const { return Loc; }

   SourceRange getSourceRange() const { return Loc; }

   /// Get the CaseStmt block from which the fallthrough transfers control.
   /// Set during Sema. (May stay null if fallthrough is invalid.)
   CaseStmt *getFallthroughSource() const { return FallthroughSource; }
   void setFallthroughSource(CaseStmt *C) {
      assert(!FallthroughSource && "fallthrough source already set?!");
      FallthroughSource = C;
   }

   /// Get the CaseStmt block to which the fallthrough transfers control.
   /// Set during Sema.
   CaseStmt *getFallthroughDest() const {
      assert(FallthroughDest && "fallthrough dest is not set until Sema");
      return FallthroughDest;
   }
   void setFallthroughDest(CaseStmt *C) {
      assert(!FallthroughDest && "fallthrough dest already set?!");
      FallthroughDest = C;
   }

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::Fallthrough;
   }
};

/// A 'case' or 'default' block of a switch statement.  Only valid as the
/// substatement of a SwitchStmt.  A case block begins either with one or more
/// CaseLabelItems or a single 'default' label.
///
/// Some examples:
/// \code
///   case 1:
///   case 2, 3:
///   case Foo(var x, var y) where x < y:
///   case 2 where foo(), 3 where bar():
///   default:
/// \endcode
///
class CaseStmt final
      : public Stmt,
      private llvm::TrailingObjects<CaseStmt, FallthroughStmt *,
      CaseLabelItem> {
   friend TrailingObjects;

   SourceLoc UnknownAttrLoc;
   SourceLoc CaseLoc;
   SourceLoc ColonLoc;

   llvm::PointerIntPair<Stmt *, 1, bool> BodyAndHasFallthrough;

   Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables;

   CaseStmt(SourceLoc CaseLoc, ArrayRef<CaseLabelItem> CaseLabelItems,
            SourceLoc UnknownAttrLoc, SourceLoc ColonLoc, Stmt *Body,
            Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables,
            Optional<bool> Implicit,
            NullablePtr<FallthroughStmt> fallthroughStmt);

public:
   static CaseStmt *
   create(AstContext &C, SourceLoc CaseLoc,
          ArrayRef<CaseLabelItem> CaseLabelItems, SourceLoc UnknownAttrLoc,
          SourceLoc ColonLoc, Stmt *Body,
          Optional<MutableArrayRef<VarDecl *>> CaseBodyVariables,
          Optional<bool> Implicit = None,
          NullablePtr<FallthroughStmt> fallthroughStmt = nullptr);

   ArrayRef<CaseLabelItem> getCaseLabelItems() const {
      return {getTrailingObjects<CaseLabelItem>(), Bits.CaseStmt.NumPatterns};
   }

   MutableArrayRef<CaseLabelItem> getMutableCaseLabelItems() {
      return {getTrailingObjects<CaseLabelItem>(), Bits.CaseStmt.NumPatterns};
   }

   unsigned getNumCaseLabelItems() const { return Bits.CaseStmt.NumPatterns; }

   NullablePtr<CaseStmt> getFallthroughDest() const {
      return const_cast<CaseStmt &>(*this).getFallthroughDest();
   }

   NullablePtr<CaseStmt> getFallthroughDest() {
      if (!hasFallthroughDest())
         return nullptr;
      return (*getTrailingObjects<FallthroughStmt *>())->getFallthroughDest();
   }

   bool hasFallthroughDest() const { return BodyAndHasFallthrough.getInt(); }

   Stmt *getBody() const { return BodyAndHasFallthrough.getPointer(); }
   void setBody(Stmt *body) { BodyAndHasFallthrough.setPointer(body); }

   /// True if the case block declares any patterns with local variable bindings.
   bool hasBoundDecls() const { return CaseBodyVariables.hasValue(); }

   /// Get the source location of the 'case' or 'default' of the first label.
   SourceLoc getLoc() const { return CaseLoc; }

   SourceLoc getStartLoc() const {
      if (UnknownAttrLoc.isValid())
         return UnknownAttrLoc;
      return getLoc();
   }
   SourceLoc getEndLoc() const { return getBody()->getEndLoc(); }
   SourceRange getLabelItemsRange() const {
      return ColonLoc.isValid() ? SourceRange(getLoc(), ColonLoc) : getSourceRange();
   }

   bool isDefault() { return getCaseLabelItems()[0].isDefault(); }

   bool hasUnknownAttr() const {
      // Note: This representation doesn't allow for synthesized @unknown cases.
      // However, that's probably sensible; the purpose of @unknown is for
      // diagnosing otherwise-non-exhaustive switches, and the user can't edit
      // a synthesized case.
      return UnknownAttrLoc.isValid();
   }

   /// Return an ArrayRef containing the case body variables of this CaseStmt.
   ///
   /// Asserts if case body variables was not explicitly initialized. In contexts
   /// where one wants a non-asserting version, \see
   /// getCaseBodyVariablesOrEmptyArray.
   ArrayRef<VarDecl *> getCaseBodyVariables() const {
      ArrayRef<VarDecl *> a = *CaseBodyVariables;
      return a;
   }

   bool hasCaseBodyVariables() const { return CaseBodyVariables.hasValue(); }

   /// Return an MutableArrayRef containing the case body variables of this
   /// CaseStmt.
   ///
   /// Asserts if case body variables was not explicitly initialized. In contexts
   /// where one wants a non-asserting version, \see
   /// getCaseBodyVariablesOrEmptyArray.
   MutableArrayRef<VarDecl *> getCaseBodyVariables() {
      return *CaseBodyVariables;
   }

   ArrayRef<VarDecl *> getCaseBodyVariablesOrEmptyArray() const {
      if (!CaseBodyVariables)
         return ArrayRef<VarDecl *>();
      ArrayRef<VarDecl *> a = *CaseBodyVariables;
      return a;
   }

   MutableArrayRef<VarDecl *> getCaseBodyVariablesOrEmptyArray() {
      if (!CaseBodyVariables)
         return MutableArrayRef<VarDecl *>();
      return *CaseBodyVariables;
   }

   static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Case; }

   size_t numTrailingObjects(OverloadToken<CaseLabelItem>) const {
      return getNumCaseLabelItems();
   }

   size_t numTrailingObjects(OverloadToken<FallthroughStmt *>) const {
      return hasFallthroughDest() ? 1 : 0;
   }
};

/// Switch statement.
class SwitchStmt final : public LabeledStmt,
      private llvm::TrailingObjects<SwitchStmt, AstNode> {
   friend TrailingObjects;

   SourceLoc SwitchLoc, LBraceLoc, RBraceLoc;
   Expr *SubjectExpr;

   SwitchStmt(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, Expr *SubjectExpr,
              SourceLoc LBraceLoc, unsigned CaseCount, SourceLoc RBraceLoc,
              Optional<bool> implicit = None)
      : LabeledStmt(StmtKind::Switch, getDefaultImplicitFlag(implicit, SwitchLoc),
                    LabelInfo),
        SwitchLoc(SwitchLoc), LBraceLoc(LBraceLoc), RBraceLoc(RBraceLoc),
        SubjectExpr(SubjectExpr) {
      Bits.SwitchStmt.CaseCount = CaseCount;
   }

public:
   /// Allocate a new SwitchStmt in the given AstContext.
   static SwitchStmt *create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc,
                             Expr *SubjectExpr,
                             SourceLoc LBraceLoc,
                             ArrayRef<AstNode> Cases,
                             SourceLoc RBraceLoc,
                             AstContext &C);

   /// Get the source location of the 'switch' keyword.
   SourceLoc getSwitchLoc() const { return SwitchLoc; }
   /// Get the source location of the opening brace.
   SourceLoc getLBraceLoc() const { return LBraceLoc; }
   /// Get the source location of the closing brace.
   SourceLoc getRBraceLoc() const { return RBraceLoc; }

   SourceLoc getLoc() const { return SwitchLoc; }

   SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(SwitchLoc); }
   SourceLoc getEndLoc() const { return RBraceLoc; }

   /// Get the subject expression of the switch.
   Expr *getSubjectExpr() const { return SubjectExpr; }
   void setSubjectExpr(Expr *e) { SubjectExpr = e; }

   ArrayRef<AstNode> getRawCases() const {
      return {getTrailingObjects<AstNode>(), Bits.SwitchStmt.CaseCount};
   }

private:
   struct AsCaseStmtWithSkippingNonCaseStmts {
      AsCaseStmtWithSkippingNonCaseStmts() {}
      Optional<CaseStmt*> operator()(const AstNode &N) const {
         if (auto *CS = llvm::dyn_cast_or_null<CaseStmt>(N.dyn_cast<Stmt*>()))
            return CS;
         return None;
      }
   };

public:
   using AsCaseStmtRange = OptionalTransformRange<ArrayRef<AstNode>,
   AsCaseStmtWithSkippingNonCaseStmts>;

   /// Get the list of case clauses.
   AsCaseStmtRange getCases() const {
      return AsCaseStmtRange(getRawCases(), AsCaseStmtWithSkippingNonCaseStmts());
   }

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::Switch;
   }
};

/// BreakStmt - The "break" and "break label" statement.
class BreakStmt : public Stmt {
   SourceLoc Loc;
   Identifier TargetName; // Named target statement, if specified in the source.
   SourceLoc TargetLoc;
   LabeledStmt *Target = nullptr;  // Target stmt, wired up by Sema.
public:
   BreakStmt(SourceLoc Loc, Identifier TargetName, SourceLoc TargetLoc,
             Optional<bool> implicit = None)
      : Stmt(StmtKind::Break, getDefaultImplicitFlag(implicit, Loc)), Loc(Loc),
        TargetName(TargetName), TargetLoc(TargetLoc) {
   }

   SourceLoc getLoc() const { return Loc; }

   Identifier getTargetName() const { return TargetName; }
   void setTargetName(Identifier N) { TargetName = N; }
   SourceLoc getTargetLoc() const { return TargetLoc; }
   void setTargetLoc(SourceLoc L) { TargetLoc = L; }

   // Manipulate the target loop/switch that is bring broken out of.  This is set
   // by sema during type checking.
   void setTarget(LabeledStmt *LS) { Target = LS; }
   LabeledStmt *getTarget() const { return Target; }

   SourceLoc getStartLoc() const { return Loc; }
   SourceLoc getEndLoc() const {
      return (TargetLoc.isValid() ? TargetLoc : Loc);
   }

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::Break;
   }
};

/// ContinueStmt - The "continue" and "continue label" statement.
class ContinueStmt : public Stmt {
   SourceLoc Loc;
   Identifier TargetName; // Named target statement, if specified in the source.
   SourceLoc TargetLoc;
   LabeledStmt *Target = nullptr;

public:
   ContinueStmt(SourceLoc Loc, Identifier TargetName, SourceLoc TargetLoc,
                Optional<bool> implicit = None)
      : Stmt(StmtKind::Continue, getDefaultImplicitFlag(implicit, Loc)), Loc(Loc),
        TargetName(TargetName), TargetLoc(TargetLoc) {
   }

   Identifier getTargetName() const { return TargetName; }
   void setTargetName(Identifier N) { TargetName = N; }
   SourceLoc getTargetLoc() const { return TargetLoc; }
   void setTargetLoc(SourceLoc L) { TargetLoc = L; }

   // Manipulate the target loop that is bring continued.  This is set by sema
   // during type checking.
   void setTarget(LabeledStmt *LS) { Target = LS; }
   LabeledStmt *getTarget() const { return Target; }

   SourceLoc getLoc() const { return Loc; }

   SourceLoc getStartLoc() const { return Loc; }
   SourceLoc getEndLoc() const {
      return (TargetLoc.isValid() ? TargetLoc : Loc);
   }

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::Continue;
   }
};

/// FailStmt - A statement that indicates a failable, which is currently
/// spelled as "return nil" and can only be used within failable initializers.
class FailStmt : public Stmt {
   SourceLoc ReturnLoc;
   SourceLoc NilLoc;

public:
   FailStmt(SourceLoc returnLoc, SourceLoc nilLoc,
            Optional<bool> implicit = None)
      : Stmt(StmtKind::Fail, getDefaultImplicitFlag(implicit, returnLoc)),
        ReturnLoc(returnLoc), NilLoc(nilLoc)
   {}

   SourceLoc getLoc() const { return ReturnLoc; }

   SourceRange getSourceRange() const { return SourceRange(ReturnLoc, NilLoc); }

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::Fail;
   }
};

/// ThrowStmt - Throws an error.
class ThrowStmt : public Stmt {
   Expr *SubExpr;
   SourceLoc ThrowLoc;

public:
   explicit ThrowStmt(SourceLoc throwLoc, Expr *subExpr)
      : Stmt(StmtKind::Throw, /*Implicit=*/false),
        SubExpr(subExpr), ThrowLoc(throwLoc) {}

   SourceLoc getThrowLoc() const { return ThrowLoc; }

   SourceLoc getStartLoc() const { return ThrowLoc; }
   SourceLoc getEndLoc() const;
   SourceRange getSourceRange() const {
      return SourceRange(ThrowLoc, getEndLoc());
   }

   Expr *getSubExpr() const { return SubExpr; }
   void setSubExpr(Expr *subExpr) { SubExpr = subExpr; }

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::Throw;
   }
};

/// PoundAssertStmt - Asserts that a condition is true, at compile time.
class PoundAssertStmt : public Stmt {
   SourceRange Range;
   Expr *Condition;
   StringRef Message;

public:
   PoundAssertStmt(SourceRange Range, Expr *condition, StringRef message)
      : Stmt(StmtKind::PoundAssert, /*Implicit=*/false),
        Range(Range),
        Condition(condition),
        Message(message) {}

   SourceRange getSourceRange() const { return Range; }

   Expr *getCondition() const { return Condition; }
   StringRef getMessage() const { return Message; }

   void setCondition(Expr *condition) { Condition = condition; }

   static bool classof(const Stmt *S) {
      return S->getKind() == StmtKind::PoundAssert;
   }
};

} // end namespace polar

#endif // POLARPHP_AST_TMT_H
